﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MoonLight.LibSocket;
using MoonLight.LibCommon;
using PVAutoTest.LibCommon;
using PVAutoTest.TestMngr;

namespace PVAutoTest.BizSimulator
{
    class Simulator : Notifier
    {

        public Simulator(Notifier parent) 
        {
            m_asyn_tcp = new AsynTcpSocket(this);
            m_msg = new AGMsg();
            m_parent = parent;
        }

        public void SetTestData(string dev_id, string event_no, int event_id, string event_msg)
        {
            m_msg.dev_id = dev_id;
            m_msg.event_no = event_no;
            m_msg.event_id = event_id;
            m_msg.event_msg = event_msg;
        }

        public void SendEvent()
        {
            m_asyn_tcp.CreateSocket();
            m_asyn_tcp.Connect(ProjectDefine.AgmIp, ProjectDefine.AgmPort);
        }

        public override void handle_message(MessageInfo msg)
        {
            switch ((CommonDefine.MsgType_e)msg.msg_type)
            {
                case CommonDefine.MsgType_e.MSG_TCP_CONNECT:
                    {
                        m_state = State_e.STATE_INIT;
                        Logger.WriteLog("connected, begin to send first msg...");
                        byte[] send_data = gen_first_msg();
                        m_asyn_tcp.Send(send_data);
                    }
                    break;
                case CommonDefine.MsgType_e.MSG_TCP_ACCEPT:
                    break;
                case CommonDefine.MsgType_e.MSG_TCP_SEND:
                    {
                        if (m_state == State_e.STATE_INIT)
                        {
                            m_state = State_e.STATE_FIRST_SEND;
                            Logger.WriteLog("first msg sended, begin to receive...");
                            m_asyn_tcp.Receive();
                        }
                        else if (m_state == State_e.STATE_FIRST_RECV) {
                            m_state = State_e.STATE_SECOND_SEND;
                            Logger.WriteLog("second msg sended, begin to receive...");
                            m_asyn_tcp.Receive();
                        }
                    }
                    break;
                case CommonDefine.MsgType_e.MSG_TCP_READ:
                    {
                        //TODO: if need to parse data from server?
                        if (m_state == State_e.STATE_FIRST_SEND)
                        {
                            string cid = parse_cid(msg.msg_data.ToString());
                            m_state = State_e.STATE_FIRST_RECV;
                            Logger.WriteLog("first response received, begin to send second msg...");
                            byte[] send_data = gen_second_msg(cid);
                            m_asyn_tcp.Send(send_data);
                        }
                        else if (m_state == State_e.STATE_SECOND_SEND)
                        {
                            m_state = State_e.STATE_CLOSEING;
                            Logger.WriteLog("second response received, close connection...");
                            m_asyn_tcp.Close();
                        }
                    }
                    break;
                case CommonDefine.MsgType_e.MSG_TCP_CLOSE:
                    {
                        //notify upper layer that the interaction has been finished.
                        m_state = State_e.STATE_CLOSED;
                        Logger.WriteLog("connection closed");
                        MessageInfo sim_msg = new MessageInfo(ProjectDefine.MsgType_e.MSG_EVENT_FINISHED);
                        m_parent.handle_message(sim_msg);
                    }
                    break;
                default:
                    Logger.WriteLog("unknown msg type [" + msg.msg_type.ToString() + "]");
                    break;
            }
        }

        private byte[] gen_first_msg()
        {
            string date = gen_date();
            string content = "AGMGR01         US002010701" + m_msg.dev_id + "                              0000" + date + "000000AGMGR01EVT          ";
            int len = content.Length;

            byte[] len_b = new byte[4];
            len_b[0] = (byte)(len >> 24);
            len_b[1] = (byte)(len >> 16);
            len_b[2] = (byte)(len >> 8);
            len_b[3] = (byte)(len);

            byte[] msg_bytes = Encoding.UTF8.GetBytes(content);

            byte[] send_data = new byte[len + 4];
            Buffer.BlockCopy(len_b, 0, send_data, 0, len_b.Length);
            Buffer.BlockCopy(msg_bytes, 0, send_data, 4, msg_bytes.Length);

            return send_data;
        }

        private byte[] gen_second_msg(string cid)
        {
            string date = gen_date();
            string date2 = gen_date2();
            string eventid = gen_eventid();

            //string content_tmp = "AGMGR01         CS310" + "0000" + "01" + m_msg.dev_id + "                              0000" + date + "00" + cid + "AGMGR01EVT          01" + eventid + "00000000001DX011101" + eventid + "06" + m_msg.dev_id + date + "010" + m_msg.event_no + "0069" + date2 + " Event 00" + eventid + " from ProView Event Simulation...\0";
            string content_tmp = "AGMGR01         CS310" + "0000" + "01" + m_msg.dev_id + "                              0000" + date + "00" + cid + "AGMGR01EVT          01" + eventid + "00000000001DX011101" + eventid + "06" + m_msg.dev_id + date + "010" + m_msg.event_no + "0069" + m_msg.event_msg + "\0";
            int len = content_tmp.Length;
            string len_str = string.Format("{0:D4}",len);
            //string content = "AGMGR01         CS310" + len_str + "01" + m_msg.dev_id + "                              0000" + date + "00" + cid + "AGMGR01EVT          01" + eventid + "00000000001DX011101" + eventid + "06" + m_msg.dev_id + date + "010" + m_msg.event_no + "0069" + date2 + " Event 00" + eventid + " from ProView Event Simulation...\0";
            string content = "AGMGR01         CS310" + len_str + "01" + m_msg.dev_id + "                              0000" + date + "00" + cid + "AGMGR01EVT          01" + eventid + "00000000001DX011101" + eventid + "06" + m_msg.dev_id + date + "010" + m_msg.event_no + "0069" + m_msg.event_msg + "\0";

            byte[] len_b = new byte[4];
            len_b[0] = (byte)(len >> 24);
            len_b[1] = (byte)(len >> 16);
            len_b[2] = (byte)(len >> 8);
            len_b[3] = (byte)(len);

            
            byte[] msg_bytes = Encoding.UTF8.GetBytes(content);

            byte[] send_data = new byte[len + 4];
            Buffer.BlockCopy(len_b, 0, send_data, 0, len_b.Length);
            Buffer.BlockCopy(msg_bytes, 0, send_data, 4, msg_bytes.Length);

            return send_data;
        }

        private string gen_date()
        {
            string year = string.Format("{0:D4}", DateTime.Now.Year);
            string month = string.Format("{0:D2}", DateTime.Now.Month);
            string day = string.Format("{0:D2}", DateTime.Now.Day);
            string hour = string.Format("{0:D2}", DateTime.Now.Hour);
            string min = string.Format("{0:D2}", DateTime.Now.Minute);
            string sec = string.Format("{0:D2}", DateTime.Now.Second);
            string date = year + month + day + hour + min + sec;
            return date;
        }

        private string gen_date2()
        {
            return DateTime.Now.ToString();
        }

        private string gen_eventid()
        {
            string eventid = string.Format("{0:D6}", m_msg.event_id);
            return eventid;
        }

        private string parse_cid(string msg)
        {
            string cid = msg.Substring(87, 4);
            return cid;
        }

        private AsynTcpSocket m_asyn_tcp;
        private State_e m_state;
        private AGMsg m_msg;
        private Notifier m_parent;
    }

    public enum State_e
    {
        STATE_INIT = 1,
        STATE_FIRST_SEND,
        STATE_FIRST_RECV,
        STATE_SECOND_SEND,
        STATE_SECOND_RECV,
        STATE_CLOSEING,
        STATE_CLOSED,
    }

    class AGMsg
    {
        public AGMsg() { }
        ~AGMsg() { }

        public string dev_id = "";
        public string event_no = "";
        public int event_id = 0;
        public string event_msg = "";
    }
}
